package com.essence.grabiec104.grab.router;

import com.google.gson.Gson;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Aspect
@Component("RouterService")
@DependsOn("SpringContextHolder")
public class RouterService {
    private static final Logger LOG = LoggerFactory.getLogger(RouterService.class);
    public final Map<String, Method> routerMap = new HashMap<>();

    /**
     * @brief 初始化路由
     * @details 在容器初始化完成后，遍历所有带有 @Component 注解的类，查找是否有 @Router 注解的方法，
     */
    @EventListener(ContextRefreshedEvent.class)
    public void init() {
        ApplicationContext appCtx = SpringContextHolder.getApplicationContext();
        Map<String, Object> beans = appCtx.getBeansWithAnnotation(RouterComponent.class);
        for (Object bean : beans.values()) {
            // 获取目标类，处理AOP代理的情况
            Class<?> targetClass = AopUtils.getTargetClass(bean);
            if(targetClass.isAnnotationPresent(RouterComponent.class)) {
                RouterComponent routerComponentAnnotation = targetClass.getAnnotation(RouterComponent.class);
                String rcValue = routerComponentAnnotation.value();
                // 获取所有声明的方法
                Method[] methods = ReflectionUtils.getAllDeclaredMethods(targetClass);
                for (Method method : methods) {
                    if (method.isAnnotationPresent(Router.class)) {
                        Router routerAnnotation = method.getAnnotation(Router.class);
                        String routerName = routerAnnotation.value();
                        routerMap.put(routerName, method);
                        LOG.info("注册路由: {}", routerName);
                    }
                }
            }

        }
    }

    /**
     * @brief 调用路由方法
     * @details 根据路由名称，调用对应的方法，并将请求体转换为指定类型参数, 对应的方法只能接收一个参数，且参数类型必须与请求体匹配，否则会抛出异常。
     */
    public Object invokeRouter(String routerName, byte[] requestBody) throws Exception {
        Method targetMethod = routerMap.get(routerName);
        if (targetMethod == null) {
            LOG.info("No method found for routerName: {}", routerName);
            return null;
        }
        // 获取目标 Bean
        Object targetBean = SpringContextHolder.getApplicationContext().getBean(targetMethod.getDeclaringClass());
        // 检查目标方法的参数类型
        Type[] parameterTypes = targetMethod.getGenericParameterTypes();
        if (parameterTypes.length != 1) {
            throw new IllegalArgumentException("Target method must have exactly one parameter");
        }

        Object convertedParam;
        if (parameterTypes[0].equals(byte[].class)) {
            convertedParam = requestBody;
        } else if (parameterTypes[0].equals(String.class)) {
            convertedParam = new String(requestBody, StandardCharsets.UTF_8);
        } else if (parameterTypes[0].equals(Integer.class)) {
            try {
                convertedParam = Integer.parseInt(new String(requestBody, StandardCharsets.UTF_8));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Failed to convert request body to integer");
            }
        } else if (parameterTypes[0].equals(Long.class)) {
            try {
                convertedParam = Long.parseLong(new String(requestBody, StandardCharsets.UTF_8));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Failed to convert request body to long");
            }
        } else if (parameterTypes[0].equals(Double.class)) {
            try {
                convertedParam = Double.parseDouble(new String(requestBody, StandardCharsets.UTF_8));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Failed to convert request body to double");
            }
        } else if (parameterTypes[0].equals(Boolean.class)) {
            try {
                convertedParam = Boolean.parseBoolean(new String(requestBody, StandardCharsets.UTF_8));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Failed to convert request body to boolean");
            }
        } else if (parameterTypes[0].equals(List.class)) {
            Gson gson = new Gson();
            convertedParam = gson.fromJson(new String(requestBody, StandardCharsets.UTF_8), parameterTypes[0]);
        } else {
            Gson gson = new Gson();
            convertedParam = gson.fromJson(new String(requestBody, StandardCharsets.UTF_8), parameterTypes[0]);
        }

        // 调用目标方法
        try {
            return targetMethod.invoke(targetBean, convertedParam);
        } catch (Exception e) {
            LOG.error("Failed to invoke method: {}", targetMethod.getName(), e);
            return "error";
        }
    }
}
